package com.sunlands.qdcy.deskmate.web;

import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayResponse;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.sunlands.qdcy.deskmate.common.annotation.AutoLog;
import com.sunlands.qdcy.deskmate.constant.CommonResultMessage;
import com.sunlands.qdcy.deskmate.dao.pojo.PaymentAliPayNotifyRecordDO;
import com.sunlands.qdcy.deskmate.enums.AlipayTradeStatus;
import com.sunlands.qdcy.deskmate.service.AlipayService;
import com.sunlands.qdcy.deskmate.service.OrderRecordService;
import com.sunlands.qdcy.deskmate.vo.BusinessResult;
import com.sunlands.qdcy.deskmate.vo.Order;
import com.sunlands.qdcy.deskmate.vo.feign.VipSetMealVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.util.Asserts;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * @author anjl
 * 支付宝app支付，订单创建，是在手机调起支付宝，并且输入了正确的密码，才会创建订单
 */

@Slf4j
@RestController
@RequestMapping("/pay/alipay")
@Api(tags = {"支付宝相关接口"}, description = "支付宝支付")
public class AlipayController extends BaseController {


    private final String FAIL = "fail";
    private final String SUCCESS = "success";

    @Autowired
    private OrderRecordService orderRecordService;
    @Autowired
    private AlipayService alipayService;
    @Resource(name = "taskExecutor")
    private AsyncTaskExecutor taskExecutor;


    @AutoLog
    @PreAuthorize("isAuthenticated()")
    @PostMapping("/create-order")
    @ApiOperation(value = "APP调用-支付宝支付下单接口,只传 goodsNumber即可", response = AlipayTradeAppPayResponse.class)
    public BusinessResult<AlipayResponse> createOrder(@RequestBody Order order) throws AlipayApiException {
        //校验信息
        Asserts.notNull(order.getGoodsNumber(), "商品编号不能为空！");
        order.setUserId(currentUserId());
        //调用vip服务获取商品信息，完善产品信息
        VipSetMealVO setMeal = userCenterService.getVipSetMeal(order.getGoodsNumber()).getData();
        Asserts.notNull(setMeal, "没有查询到对应的商品信息！id = " + order.getGoodsNumber());
        order.setTotalAmount(setMeal.getPrice());
        order.setSubject(setMeal.getName());
        order.setBody(setMeal.getContent());
        BigDecimal totalAmount = order.getTotalAmount().setScale(2, BigDecimal.ROUND_HALF_UP);
        order.setTotalAmount(totalAmount);

        AlipayTradeAppPayResponse response = alipayService.createOrder(order);
        if (Objects.nonNull(response) && response.isSuccess()) {
            log.info("支付宝下单成功 alipayResponse = {}", response);
            return BusinessResult.createSuccessInstance(response);
        } else {
            log.error("app支付接口异常 response = {}", response);
            return BusinessResult.createInstance(CommonResultMessage.FAIL.code, "支付宝下单错误");
        }
    }

    /**
     * 支付宝支付异步回调
     *
     * @param request request
     * @return String
     */
    @AutoLog
    @ApiOperation(value = "支付宝调用-支付成功通知", response = String.class)
    @PostMapping("/notify")
    public String notify(HttpServletRequest request) throws AlipayApiException {
        Map<String, String> params = buildParamForSign(request);
        // 签名验证
        PaymentAliPayNotifyRecordDO notifyRecord = alipayService.saveNotifyRecord(params);
        log.info("支付宝支付回调 验证结果 = {}", notifyRecord);
        if (!notifyRecord.isSignVerified()) {
            log.warn("支付宝支付回调 支付校验失败：params={}", JSONObject.toJSONString(notifyRecord));
            return FAIL;
        }
        String outTradeNo = notifyRecord.getOutTradeNo();

        //具体判断每个状态码
        if (AlipayTradeStatus.TRADE_SUCCESS.toString().equals(notifyRecord.getTradeStatus())
                || AlipayTradeStatus.TRADE_FINISHED.toString().equals(notifyRecord.getTradeStatus())) {
            //是否首次变成已支付
            if (notifyRecord.isFirstChangeToPayed()) {
                log.info("支付宝订单回调：订单支付成功：outTradeNo={},result={}", outTradeNo, notifyRecord.isFirstChangeToPayed());
                taskExecutor.execute(() -> orderRecordService.sendGoods(outTradeNo));
            }
            //订单关闭（超时关闭，涉及退款 也有退款关闭）
        } else if (AlipayTradeStatus.TRADE_CLOSED.name().equals(notifyRecord.getTradeStatus())) {
            log.info("支付宝订单回调：订单关闭：outTradeNo={},result={}", outTradeNo, notifyRecord.isFirstChangeToPayed());
            taskExecutor.execute(() -> orderRecordService.closeOrder(outTradeNo));
        } else {
            log.error("支付宝订单回调：未知订单状态：outTradeNo={},result={}", outTradeNo, notifyRecord.isFirstChangeToPayed());
        }
        return SUCCESS;
    }


    @AutoLog
    @ApiOperation(value = "工具-支付宝状态查询", response = BusinessResult.class)
    @GetMapping("/query")
    public BusinessResult<AlipayResponse> notify(@RequestParam String outTradeNo) {
        return BusinessResult.createSuccessInstance(alipayService.pullOrderStatus(outTradeNo));
    }

    private Map<String, String> buildParamForSign(HttpServletRequest request) {
        Map<String, String> params = new HashMap<String, String>();
        Map<String, String[]> requestParams = request.getParameterMap();
        for (Map.Entry<String, String[]> entry : requestParams.entrySet()) {
            String name = entry.getKey();
            String[] values = entry.getValue();
            StringBuilder b = new StringBuilder();
            boolean first = false;
            for (String val : values) {
                if (first) {
                    b.append(",");
                }
                b.append(val);
                first = true;
            }
            // 乱码解决，这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化
            // valueStr = new String(valueStr.getBytes("ISO-8859-1"), "gbk");
            params.put(name, b.toString());
        }

        return params;
    }


}